""" -*- mode: python; coding: utf-8; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
"""

import sys, pickle, python_config, pyintromit, unittest, python_runner
pyintromit.load("intromit/test/.libs/libpython_misc.so")
import libpython_misc


class test_4_misc(unittest.TestCase):

    def test_01(self):
        "Enum type at module top level"
        self.assert_("SAMP1" in dir(libpython_misc))
        self.assert_("SAMP2" in dir(libpython_misc))
        self.assert_("SAMP3" in dir(libpython_misc))
        self.assert_("SAMPLAST" in dir(libpython_misc))

    def test_02(self):
        "Enum type at module top level values"
        self.assertEqual(libpython_misc.SAMP1, 0)
        self.assertEqual(libpython_misc.SAMP2, 1)
        self.assertEqual(libpython_misc.SAMP3, 2)
        self.assertEqual(libpython_misc.SAMPLAST, 3)

    def test_03(self):
        "Enum in a struct -> check values"
        self.assertEqual(libpython_misc.embed_enum.SAMP9, 9)
        self.assertEqual(libpython_misc.embed_enum.SAMP15, 15)
        self.assertEqual(libpython_misc.embed_enum.SAMP8, 8)
        self.assertEqual(libpython_misc.embed_enum.SAMP20, -20)

    def test_04(self):
        "Enum in a struct::struct -> check values"
        self.assertEqual(libpython_misc.embed_enum.embed_struct.SAMP_ESS0, 0)
        self.assertEqual(libpython_misc.embed_enum.embed_struct.SAMP_ESS1, 1)

    def test_05(self):
        "Enum in a struct::struct::class -> check values"
        self.assertEqual(libpython_misc.embed_enum.embed_struct.embed_class.SAMP_CLASS, 0)

    def test_06(self):
        "Enum in a struct::struct::class::union -> check values"
        self.assertEqual(libpython_misc.embed_enum.embed_struct.embed_class.embed_union.SAMP_UNION, -1)

    def test_07(self):
        "Enum in a namespace -> check values"
        self.assertEqual(libpython_misc.namespace_enum.SAMP_NAMESPC, -8)
        self.assertEqual(libpython_misc.namespace_enum.SAMP_NAMESPC_LAST, -7)

    def test_08(self):
        "Class declaration inside a double namespace nest"
        self.assert_("namespace_nested" in dir(libpython_misc.namespace_enum))
        self.assert_("namespace_class" in dir(libpython_misc.namespace_enum.namespace_nested))

    def test_09(self):
        "Instantiation of classes"

        # types with unique names
        self.assertEqual(type(libpython_misc.embed_enum()), libpython_misc._embed_enum)
        self.assertEqual(type(libpython_misc.embed_enum.embed_struct.embed_class()), libpython_misc._embed_class)
        self.assertEqual(type(libpython_misc.embed_enum.embed_struct.embed_class.embed_union()), libpython_misc._embed_union)
        self.assertEqual(type(libpython_misc.namespace_enum.namespace_nested.namespace_class(6)), libpython_misc._namespace_class)

        # types with the same name (different context) in C++
        types=[getattr(libpython_misc, e) for e in dir(libpython_misc)]
        self.assert_(type(libpython_misc.embed_enum.embed_struct()) in types)
        self.assert_(type(libpython_misc.namespace_enum.namespace_nested.embed_struct()) in types)

    def test_10(self):
        "Serialization of embedded class"
        nc=libpython_misc.namespace_enum.namespace_nested.namespace_class(99)
        self.assertEqual(nc.get_x(), 99)
        self.assertEqual(nc.get_x(), pickle.loads(pickle.dumps(nc)).get_x())

    def test_11(self):
        "Embedded class doc"
        self.assertEqual("same name in different context", libpython_misc.namespace_enum.namespace_nested.embed_struct.__doc__)
        self.assertEqual("doc in members", libpython_misc.namespace_enum.namespace_nested.namespace_class.x.__doc__)
        self.assertEqual("doc to test", libpython_misc.namespace_enum.namespace_nested.namespace_class.get_x.__doc__)

    def test_12(self):
        "Basic inheritance"

        # test base class
        b=libpython_misc.base()
        self.assertEqual(b.b, -1)
        b.b+=2
        self.assertEqual(b.b, 1)
        self.assertEqual(b.get_b(), 1)
        b.set_b(-1)
        self.assertEqual(b.get_b(), -1)

        # test derived class
        d1=libpython_misc.derived1()
        self.assertEqual(d1.d1, -2)
        d1.d1+=4
        self.assertEqual(d1.d1, 2)
        self.assertEqual(d1.get_d1(), 2)
        d1.set_d1(-2)
        self.assertEqual(d1.get_d1(), -2)

        # check inheritance
        self.assertEqual(d1.b, -1)
        d1.b+=2
        self.assertEqual(d1.b, 1)
        self.assertEqual(d1.get_b(), 1)
        d1.set_b(-1)
        self.assertEqual(d1.get_b(), -1)

    def test_13(self):
        "Basic inheritance: virtual methods"
        b=libpython_misc.base()
        self.assertEqual(type(b), libpython_misc._base)
        self.assertEqual(b.virtual_method(), 99)

        d1=libpython_misc.derived1()
        b=d1.generalize_this()
        self.assertEqual(type(b), libpython_misc._derived1)
        self.assertEqual(type(d1), libpython_misc._derived1)
        self.assertEqual(d1.virtual_method(), 66)
        self.assertEqual(b.virtual_method(), 66) # derived1 method is called

    def test_14(self):
        "Basic inheritance: serialization"
        d1=libpython_misc.derived1()
        d1.b=14
        d1.d1=7.5
        self.assertEqual(d1.__getstate__(), pickle.loads(pickle.dumps(d1)).__getstate__())

    def test_15(self):
        "Basic inheritance: base -> derived1 -> derived2"
        d2=libpython_misc.derived2()
        self.assertEqual(d2.b, -1)
        self.assertEqual(d2.d1, -2)
        self.assertEqual(d2.d2, -4)
        d2.set_b(1); d2.set_d1(2); d2.set_d2(4)
        self.assertEqual(d2.get_b(), 1)
        self.assertEqual(d2.get_d1(), 2)
        self.assertEqual(d2.get_d2(), 4)
        d2.b=2; d2.d1=4; d2.d2=8
        self.assertEqual(d2.get_b(), 2)
        self.assertEqual(d2.get_d1(), 4)
        self.assertEqual(d2.get_d2(), 8)

    def test_16(self):
        "Basic inheritance: base -> derived1 -> derived2: virtual"
        d2=libpython_misc.derived2()
        d1=d2.generalize_derived1()
        b=d2.generalize_base()
        self.assertEqual(type(b), libpython_misc._derived2)
        self.assertEqual(type(d1), libpython_misc._derived2)
        self.assertEqual(type(d2), libpython_misc._derived2)
        self.assertEqual(b.virtual_method(), 33)
        self.assertEqual(d1.virtual_method(), 33)
        self.assertEqual(d2.virtual_method(), 33)

    def test_17(self):
        "Global variables: initial values"
        self.assertEqual(libpython_misc.globals.global_int, -123)
        self.assertEqual(libpython_misc.globals.global_float, 3.5)
        self.assertEqual(libpython_misc.globals.global_double, -7.8)

    def test_18(self):
        "Global objects: initialization"
        self.assertEqual(libpython_misc.globals.global_class.b, -1)
        self.assertEqual(libpython_misc.globals.global_class.d1, -2)
        self.assertEqual(libpython_misc.globals.global_class.d2, -4)
        self.assertEqual(libpython_misc.globals.global_class.virtual_method(), 33)

    def test_19(self):
        "Global object pointers: initialization"
        self.assertEqual(libpython_misc.globals.global_base.b, -1)
        self.assertEqual(libpython_misc.globals.global_base.virtual_method(), 33) # derived2 method is called

    def test_20(self):
        "Functions"

        # getters
        self.assertEqual(libpython_misc.get_global_int(), libpython_misc.globals.global_int)
        self.assertEqual(libpython_misc.get_global_float(), libpython_misc.globals.global_float)
        self.assertEqual(libpython_misc.get_global_double(), libpython_misc.globals.global_double)

        # setters
        libpython_misc.set_global_int(9999)
        self.assertEqual(libpython_misc.globals.global_int, 9999)
        libpython_misc.set_global_float(-6666)
        self.assertEqual(libpython_misc.globals.global_float, -6666)
        libpython_misc.set_global_double(0.004)
        self.assertEqual(libpython_misc.globals.global_double, 0.004)

        # leave variables with their original values
        libpython_misc.globals.global_int=-123
        libpython_misc.globals.global_float=3.5
        libpython_misc.globals.global_double=-7.8

    def test_21(self):
        "Functions: polymorphism"
        self.assertEqual(libpython_misc.func_poly(), 1)
        self.assertEqual(libpython_misc.func_poly(2), 2)
        self.assertEqual(libpython_misc.func_poly(2.2), 3)
        self.assertEqual(libpython_misc.func_poly(4, 5), 4)

    def test_22(self):
        "Functions: doc"
        self.assertEqual(libpython_misc.get_global_int.__doc__, "this is a function")

    def test_23(self):
        "Global variable inside namespace: int"
        self.assertEqual(libpython_misc.namespace_enum.global_namespace_int, -999)
        libpython_misc.namespace_enum.global_namespace_int=12345678;
        self.assertEqual(libpython_misc.namespace_enum.global_namespace_int, 12345678)
        libpython_misc.namespace_enum.global_namespace_int=-999;

    def test_24(self):
        "Global variable inside nested namespace: double"
        self.assertEqual(libpython_misc.namespace_enum.namespace_nested.global_double, 10.5)
        libpython_misc.namespace_enum.namespace_nested.global_double=-1.2345
        self.assertEqual(libpython_misc.namespace_enum.namespace_nested.global_double, -1.2345)
        libpython_misc.namespace_enum.namespace_nested.global_double=10.5

    def test_25(self):
        "Inheritance without ctor"
        base=libpython_misc.base_wo_ctor();
        deri=libpython_misc.derived_wo_ctor();
        gene=deri.generalize()

        self.assertEqual(type(base), libpython_misc._base_wo_ctor)
        self.assertEqual(type(deri), libpython_misc._derived_wo_ctor)
        self.assertEqual(type(gene), libpython_misc._derived_wo_ctor)

        self.assertEqual(base.vmethod(), 1)
        self.assertEqual(deri.vmethod(), 2)
        self.assertEqual(gene.vmethod(), 2)

    def test_26(self):
        "Inheritance ctor and dtor execution"
        exec1=libpython_misc.exec1()
        exec1.member1

        exec2=libpython_misc.exec2()
        self.assertAlmostEqual(exec2.member2*1e3, 987654, 1)
        exec2.set_member1(111.222)
        self.assertAlmostEqual(exec2.member1*1e3, 111222, 1)
        del exec2
        self.assertEqual(libpython_misc.globals.exec_global, 1<<2)

        exec3=libpython_misc.exec3()
        self.assertAlmostEqual(exec3.member2*1e3, 987654, 1)
        del exec3
        self.assertEqual(libpython_misc.globals.exec_global, 1<<2)

        exec4=libpython_misc.exec4()
        self.assertAlmostEqual(exec4.member2*1e3, 987654, 1)
        self.assertAlmostEqual(exec4.member4*1e3, 123987, 1)
        del exec4
        self.assertEqual(libpython_misc.globals.exec_global, 1<<2 | 1<<4)

    def test_27(self):
        "Functions inside a namespace"
        self.assertEqual(libpython_misc.func_namespace.functions.namespaced_func(3, 4), -7+3+4)

if __name__ == '__main__':

    suite = unittest.TestLoader().loadTestsFromTestCase(test_4_misc)
    result=python_runner.BasicTestRunner(iterations=len(sys.argv)>1 and sys.argv[1] or 1,
	stream=len(sys.argv)>2 and open(sys.argv[2], "w") or sys.stderr).run(suite)
    sys.exit(not result.wasSuccessful())
